#ifndef __EPSILON_TESTBED__STATES_H__
#define __EPSILON_TESTBED__STATES_H__

#include "../Epsilon/types.h"
#include "../Epsilon/strings.h"

class eFont;

//
// Render Path Prototypes 
//
typedef void (CALLBACK* PFN_ETB_FRAME_FUNC)  (void);
typedef bool (CALLBACK* PFN_ETB_DRAW_FUNC)   (void);
typedef void (CALLBACK* PFN_ETB_CAMERA_FUNC) (void);
typedef bool (CALLBACK* PFN_ETB_UPDATE_FUNC) (void);
typedef bool (CALLBACK* PFN_ETB_LOAD_FUNC)   (void*);

//
// Event Handlers
//
typedef void (CALLBACK* PFN_ETB_DEBUG_FUNC)       (void);
typedef void (CALLBACK* PFN_ETB_INFO_FUNC)        (void);
typedef void (CALLBACK* PFN_ETB_WARNING_FUNC)     (void);
typedef void (CALLBACK* PFN_ETB_FATAL_ERROR_FUNC) (void);
typedef void (CALLBACK* PFN_ETB_TERMINATE_FUNC)   (int);


class eTestbedModuleStates {
public:
  virtual ~eTestbedModuleStates (void) { };
};

class eTB_RenderWindow;
class eTB_Input;
class eTB_Console;
class eTB_Console_Render;
class eTB_CommandProcessor;

class eTestbedStates
{
public:
  eTestbedModuleStates* mod_states;     ///< Module-specific states

  eFont*                r_font;         ///< Primary raster font
  eFont*                r_console_font; ///< Console font
  bool                  r_stat_overlay; ///< Draw text like FPS?
  bool                  r_batch_print;  ///< Combine font printing into batches

  bool                  cl_verbose;     ///< Verbosity

  int                   r_window_res_x;
  int                   r_window_res_y;

  ///
  /// TODO: Replace with keyboard event listeners...
  ///
  bool                  key_states [256]; ///< Last known state for each key

  ///
  /// Camera States
  ///
  bool                  cl_fly;         ///< Whether or not to "fly"...

  eTB_RenderWindow*     window;         ///< The primary window
  eTB_Input*            input;          ///< The primary input (modules should
                                        ///                     subclass this)
  eTB_Console*          console;        ///< Primary text I/O facility
  eTB_CommandProcessor* command;        ///< Primary command processor
  eTB_Console_Render*   gui_console;    ///< GUI console, displays the text in
                                        ///    console, but using a GUI.

  //
  // Render Paths
  //
  PFN_ETB_FRAME_FUNC  render_frame;
  PFN_ETB_DRAW_FUNC   primary_draw;
  PFN_ETB_CAMERA_FUNC handle_camera;
  PFN_ETB_UPDATE_FUNC timed_updates;
  PFN_ETB_LOAD_FUNC   load_resources;

  //
  // Event Handlers
  //
  PFN_ETB_FATAL_ERROR_FUNC fatal_error;
  PFN_ETB_TERMINATE_FUNC   terminate;


  eTestbedStates (void) {
#ifdef _DEBUG
    cl_verbose     = true;
#else
    cl_verbose     = false;
#endif

    cl_fly         = false;

    r_font         = NULL;
    r_console_font = NULL;
    r_stat_overlay = true;
    r_batch_print  = true;

    /* Assign a dummy value that is likely to be valid on
         any display device encountered... */
    r_window_res_x = r_window_res_y = 256;

    //int   r_rgba_bits;
    //int   r_z_bits;
    //int   r_stencil_bits;

    mod_states     = NULL; // Module states

    window         = NULL;
    input          = NULL;
    console        = NULL; /* NOTE: Initialize this ASAP! */
    gui_console    = NULL;
  }


  bool CALLBACK LoadResources (void* usr_data = NULL)
  {
    if (load_resources)
      return load_resources (usr_data);

    return true;
  }

  bool CALLBACK TimedUpdates (void)
  {
    if (timed_updates)
      return timed_updates ();

    return true;
  }

  void CALLBACK RenderFrame (void)
  {
    if (render_frame)
      render_frame ();
  }

  ///
  /// Special method that doesn't actually render an entire frame...
  ///
  ///  * Used by the specialized Screenshot methods.
  ///
  bool CALLBACK PrimaryDraw (void)
  {
    if (primary_draw)
      return primary_draw ();

    return false;
  }

  void CALLBACK HandleCamera (void)
  {
    if (handle_camera)
      handle_camera ();
  }

  void SetConsolePrompt (const TCHAR* szPrompt) {
    ////_tcsncpy (console_prompt, szPrompt, 64);
  }

  void CALLBACK FatalError (void) {
    if (fatal_error)
      fatal_error ();

    /// If we have no fatal error callback, we have
    /// no choice but to terminate the program...
    else
      return;
      ////exit (-1);
  }

  void CALLBACK Terminate (int reason) {
    if (terminate)
      terminate (reason);
  }

  //
  // Shared Begin Frame routine: Allows us to hook shared begin-frame mechanisms into ALL
  //                             render modules.
  //
  void BeginFrame (void) {
///    window->render.begin_frame ();
  }

  //
  // Shared End Frame routine: Allows us to hook shared end-of-frame mechanisms into ALL
  //                           render modules.
  //
  void
  EndFrame (void) {
///    console.Draw ();

///    window->render.end_frame ();
  }
};

extern eTestbedStates* states;

#endif /* __EPSILON_TESTBED__STATES_H__ */
